
var browser = function(){
    var agent = navigator.userAgent.toLowerCase(),
        opera = window.opera,
        browser = {
        ie		:  /(msie\s|trident.*rv:)([\w.]+)/.test(agent),
        opera	: ( !!opera && opera.version ),
        webkit	: ( agent.indexOf( ' applewebkit/' ) > -1 ),
        mac	: ( agent.indexOf( 'macintosh' ) > -1 ),
        quirks : ( document.compatMode == 'BackCompat' )
    };
    browser.gecko =( navigator.product == 'Gecko' && !browser.webkit && !browser.opera && !browser.ie);
    var version = 0;
    if ( browser.ie ){
        var v1 =  agent.match(/(?:msie\s([\w.]+))/);
        var v2 = agent.match(/(?:trident.*rv:([\w.]+))/);
        if(v1 && v2 && v1[1] && v2[1]){
            version = Math.max(v1[1]*1,v2[1]*1);
        }else if(v1 && v1[1]){
            version = v1[1]*1;
        }else if(v2 && v2[1]){
            version = v2[1]*1;
        }else{
            version = 0;
        }
        browser.ie11Compat = document.documentMode == 11;
        browser.ie9Compat = document.documentMode == 9;
        browser.ie8 = !!document.documentMode;
        browser.ie8Compat = document.documentMode == 8;
        browser.ie7Compat = ( ( version == 7 && !document.documentMode )
                || document.documentMode == 7 );
        browser.ie6Compat = ( version < 7 || browser.quirks );
        browser.ie9above = version > 8;
        browser.ie9below = version < 9;
        browser.ie11above = version > 10;
        browser.ie11below = version < 11;
    }
    if ( browser.gecko ){
        var geckoRelease = agent.match( /rv:([\d\.]+)/ );
        if ( geckoRelease )
        {
            geckoRelease = geckoRelease[1].split( '.' );
            version = geckoRelease[0] * 10000 + ( geckoRelease[1] || 0 ) * 100 + ( geckoRelease[2] || 0 ) * 1;
        }
    }
    if (/chrome\/(\d+\.\d)/i.test(agent)) {
        browser.chrome = + RegExp['\x241'];
    }
    if(/(\d+\.\d)?(?:\.\d)?\s+safari\/?(\d+\.\d+)?/i.test(agent) && !/chrome/i.test(agent)){
    	browser.safari = + (RegExp['\x241'] || RegExp['\x242']);
    }
    if ( browser.opera )
        version = parseFloat( opera.version() );
    if ( browser.webkit )
        version = parseFloat( agent.match( / applewebkit\/(\d+)/ )[1] );
    browser.version = version;
    browser.isCompatible =
        !browser.mobile && (
        ( browser.ie && version >= 6 ) ||
        ( browser.gecko && version >= 10801 ) ||
        ( browser.opera && version >= 9.5 ) ||
        ( browser.air && version >= 1 ) ||
        ( browser.webkit && version >= 522 ) ||
        false );
    return browser;
}();

var utils = {
	    each : function(obj, iterator, context) {
	        if (obj == null) return;
	        if (obj.length === +obj.length) {
	            for (var i = 0, l = obj.length; i < l; i++) {
	                if(iterator.call(context, obj[i], i, obj) === false)
	                    return false;
	            }
	        } else {
	            for (var key in obj) {
	                if (obj.hasOwnProperty(key)) {
	                    if(iterator.call(context, obj[key], key, obj) === false)
	                        return false;
	                }
	            }
	        }
	    },
	    makeInstance:function (obj) {
	        var noop = new Function();
	        noop.prototype = obj;
	        obj = new noop;
	        noop.prototype = null;
	        return obj;
	    },
	    extend:function (t, s, b) {
	        if (s) {
	            for (var k in s) {
	                if (!b || !t.hasOwnProperty(k)) {
	                    t[k] = s[k];
	                }
	            }
	        }
	        return t;
	    },

	    extend2:function (t) {
	        var a = arguments;
	        for (var i = 1; i < a.length; i++) {
	            var x = a[i];
	            for (var k in x) {
	                if (!t.hasOwnProperty(k)) {
	                    t[k] = x[k];
	                }
	            }
	        }
	        return t;
	    },
	    inherits:function (subClass, superClass) {
	        var oldP = subClass.prototype,
	            newP = utils.makeInstance(superClass.prototype);
	        utils.extend(newP, oldP, true);
	        subClass.prototype = newP;
	        return (newP.constructor = subClass);
	    },
	    bind:function (fn, context) {
	        return function () {
	            return fn.apply(context, arguments);
	        };
	    },
	    defer:function (fn, delay, exclusion) {
	        var timerID;
	        return function () {
	            if (exclusion) {
	                clearTimeout(timerID);
	            }
	            timerID = setTimeout(fn, delay);
	        };
	    },
	    indexOf:function (array, item, start) {
	        var index = -1;
	        start = this.isNumber(start) ? start : 0;
	        this.each(array, function (v, i) {
	            if (i >= start && v === item) {
	                index = i;
	                return false;
	            }
	        });
	        return index;
	    },
	    removeItem:function (array, item) {
	        for (var i = 0, l = array.length; i < l; i++) {
	            if (array[i] === item) {
	                array.splice(i, 1);
	                i--;
	            }
	        }
	    },
	    trim:function (str) {
	        return str.replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g, '');
	    },
	    listToMap:function (list) {
	        if (!list)return {};
	        list = utils.isArray(list) ? list : list.split(',');
	        for (var i = 0, ci, obj = {}; ci = list[i++];) {
	            obj[ci.toUpperCase()] = obj[ci] = 1;
	        }
	        return obj;
	    },
	    unhtml:function (str, reg) {
	        return str ? str.replace(reg || /[&<">'](?:(amp|lt|quot|gt|#39|nbsp|#\d+);)?/g, function (a, b) {
	            if (b) {
	                return a;
	            } else {
	                return {
	                    '<':'&lt;',
	                    '&':'&amp;',
	                    '"':'&quot;',
	                    '>':'&gt;',
	                    "'":'&#39;'
	                }[a]
	            }

	        }) : '';
	    },
	    html:function (str) {
	        return str ? str.replace(/&((g|l|quo)t|amp|#39|nbsp);/g, function (m) {
	            return {
	                '&lt;':'<',
	                '&amp;':'&',
	                '&quot;':'"',
	                '&gt;':'>',
	                '&#39;':"'",
	                '&nbsp;':' '
	            }[m]
	        }) : '';
	    },
	    cssStyleToDomStyle:function () {
	        var test = document.createElement('div').style,
	            cache = {
	                'float':test.cssFloat != undefined ? 'cssFloat' : test.styleFloat != undefined ? 'styleFloat' : 'float'
	            };

	        return function (cssName) {
	            return cache[cssName] || (cache[cssName] = cssName.toLowerCase().replace(/-./g, function (match) {
	                return match.charAt(1).toUpperCase();
	            }));
	        };
	    }(),
	    loadFile:function () {
	        var tmpList = [];

	        function getItem(doc, obj) {
	            try {
	                for (var i = 0, ci; ci = tmpList[i++];) {
	                    if (ci.doc === doc && ci.url == (obj.src || obj.href)) {
	                        return ci;
	                    }
	                }
	            } catch (e) {
	                return null;
	            }

	        }

	        return function (doc, obj, fn) {
	            var item = getItem(doc, obj);
	            if (item) {
	                if (item.ready) {
	                    fn && fn();
	                } else {
	                    item.funs.push(fn)
	                }
	                return;
	            }
	            tmpList.push({
	                doc:doc,
	                url:obj.src || obj.href,
	                funs:[fn]
	            });
	            if (!doc.body) {
	                var html = [];
	                for (var p in obj) {
	                    if (p == 'tag')continue;
	                    html.push(p + '="' + obj[p] + '"')
	                }
	                doc.write('<' + obj.tag + ' ' + html.join(' ') + ' ></' + obj.tag + '>');
	                return;
	            }
	            if (obj.id && doc.getElementById(obj.id)) {
	                return;
	            }
	            var element = doc.createElement(obj.tag);
	            delete obj.tag;
	            for (var p in obj) {
	                element.setAttribute(p, obj[p]);
	            }
	            element.onload = element.onreadystatechange = function () {
	                if (!this.readyState || /loaded|complete/.test(this.readyState)) {
	                    item = getItem(doc, obj);
	                    if (item.funs.length > 0) {
	                        item.ready = 1;
	                        for (var fi; fi = item.funs.pop();) {
	                            fi();
	                        }
	                    }
	                    element.onload = element.onreadystatechange = null;
	                }
	            };
	            element.onerror = function () {
	                throw Error('The load ' + (obj.href || obj.src) + ' fails,check the url settings of file ueditor.config.js ')
	            };
	            doc.getElementsByTagName("head")[0].appendChild(element);
	        }
	    }(),
	    isEmptyObject:function (obj) {
	        if (obj == null) return true;
	        if (this.isArray(obj) || this.isString(obj)) return obj.length === 0;
	        for (var key in obj) if (obj.hasOwnProperty(key)) return false;
	        return true;
	    },
	    fixColor:function (name, value) {
	        if (/color/i.test(name) && /rgba?/.test(value)) {
	            var array = value.split(",");
	            if (array.length > 3)
	                return "";
	            value = "#";
	            for (var i = 0, color; color = array[i++];) {
	                color = parseInt(color.replace(/[^\d]/gi, ''), 10).toString(16);
	                value += color.length == 1 ? "0" + color : color;
	            }
	            value = value.toUpperCase();
	        }
	        return  value;
	    },
	    optCss:function (val) {
	        var padding, margin, border;
	        val = val.replace(/(padding|margin|border)\-([^:]+):([^;]+);?/gi, function (str, key, name, val) {
	            if (val.split(' ').length == 1) {
	                switch (key) {
	                    case 'padding':
	                        !padding && (padding = {});
	                        padding[name] = val;
	                        return '';
	                    case 'margin':
	                        !margin && (margin = {});
	                        margin[name] = val;
	                        return '';
	                    case 'border':
	                        return val == 'initial' ? '' : str;
	                }
	            }
	            return str;
	        });

	        function opt(obj, name) {
	            if (!obj) {
	                return '';
	            }
	            var t = obj.top , b = obj.bottom, l = obj.left, r = obj.right, val = '';
	            if (!t || !l || !b || !r) {
	                for (var p in obj) {
	                    val += ';' + name + '-' + p + ':' + obj[p] + ';';
	                }
	            } else {
	                val += ';' + name + ':' +
	                    (t == b && b == l && l == r ? t :
	                        t == b && l == r ? (t + ' ' + l) :
	                            l == r ? (t + ' ' + l + ' ' + b) : (t + ' ' + r + ' ' + b + ' ' + l)) + ';'
	            }
	            return val;
	        }

	        val += opt(padding, 'padding') + opt(margin, 'margin');
	        return val.replace(/^[ \n\r\t;]*|[ \n\r\t]*$/, '').replace(/;([ \n\r\t]+)|\1;/g, ';')
	            .replace(/(&((l|g)t|quot|#39))?;{2,}/g, function (a, b) {
	                return b ? b + ";;" : ';'
	            });
	    },
	    clone:function (source, target) {
	        var tmp;
	        target = target || {};
	        for (var i in source) {
	            if (source.hasOwnProperty(i)) {
	                tmp = source[i];
	                if (typeof tmp == 'object') {
	                    target[i] = utils.isArray(tmp) ? [] : {};
	                    utils.clone(source[i], target[i])
	                } else {
	                    target[i] = tmp;
	                }
	            }
	        }
	        return target;
	    },
	    transUnitToPx:function (val) {
	        if (!/(pt|cm)/.test(val)) {
	            return val
	        }
	        var unit;
	        val.replace(/([\d.]+)(\w+)/, function (str, v, u) {
	            val = v;
	            unit = u;
	        });
	        switch (unit) {
	            case 'cm':
	                val = parseFloat(val) * 25;
	                break;
	            case 'pt':
	                val = Math.round(parseFloat(val) * 96 / 72);
	        }
	        return val + (val ? 'px' : '');
	    },
	    domReady:function () {

	        var fnArr = [];

	        function doReady(doc) {
	            //确保onready只执行一次
	            doc.isReady = true;
	            for (var ci; ci = fnArr.pop(); ci()) {
	            }
	        }

	        return function (onready, win) {
	            win = win || window;
	            var doc = win.document;
	            onready && fnArr.push(onready);
	            if (doc.readyState === "complete") {
	                doReady(doc);
	            } else {
	                doc.isReady && doReady(doc);
	                if (browser.ie && browser.version != 11) {
	                    (function () {
	                        if (doc.isReady) return;
	                        try {
	                            doc.documentElement.doScroll("left");
	                        } catch (error) {
	                            setTimeout(arguments.callee, 0);
	                            return;
	                        }
	                        doReady(doc);
	                    })();
	                    win.attachEvent('onload', function () {
	                        doReady(doc)
	                    });
	                } else {
	                    doc.addEventListener("DOMContentLoaded", function () {
	                        doc.removeEventListener("DOMContentLoaded", arguments.callee, false);
	                        doReady(doc);
	                    }, false);
	                    win.addEventListener('load', function () {
	                        doReady(doc)
	                    }, false);
	                }
	            }

	        }
	    }(),
	    cssRule:browser.ie && browser.version != 11 ? function (key, style, doc) {
	        var indexList, index;
	        if(style === undefined || style && style.nodeType && style.nodeType == 9){
	            //获取样式
	            doc = style && style.nodeType && style.nodeType == 9 ? style : (doc || document);
	            indexList = doc.indexList || (doc.indexList = {});
	            index = indexList[key];
	            if(index !==  undefined){
	                return doc.styleSheets[index].cssText
	            }
	            return undefined;
	        }
	        doc = doc || document;
	        indexList = doc.indexList || (doc.indexList = {});
	        index = indexList[key];
	        //清除样式
	        if(style === ''){
	            if(index!== undefined){
	                doc.styleSheets[index].cssText = '';
	                delete indexList[key];
	                return true
	            }
	            return false;
	        }

	        //添加样式
	        if(index!== undefined){
	            sheetStyle =  doc.styleSheets[index];
	        }else{
	            sheetStyle = doc.createStyleSheet('', index = doc.styleSheets.length);
	            indexList[key] = index;
	        }
	        sheetStyle.cssText = style;
	    }: function (key, style, doc) {
	        var head, node;
	        if(style === undefined || style && style.nodeType && style.nodeType == 9){
	            //获取样式
	            doc = style && style.nodeType && style.nodeType == 9 ? style : (doc || document);
	            node = doc.getElementById(key);
	            return node ? node.innerHTML : undefined;
	        }
	        doc = doc || document;
	        node = doc.getElementById(key);

	        //清除样式
	        if(style === ''){
	            if(node){
	                node.parentNode.removeChild(node);
	                return true
	            }
	            return false;
	        }

	        //添加样式
	        if(node){
	            node.innerHTML = style;
	        }else{
	            node = doc.createElement('style');
	            node.id = key;
	            node.innerHTML = style;
	            doc.getElementsByTagName('head')[0].appendChild(node);
	        }
	    },
	    sort:function(array,compareFn){
	        compareFn = compareFn || function(item1, item2){ return item1.localeCompare(item2);};
	        for(var i= 0,len = array.length; i<len; i++){
	            for(var j = i,length = array.length; j<length; j++){
	                if(compareFn(array[i], array[j]) > 0){
	                    var t = array[i];
	                    array[i] = array[j];
	                    array[j] = t;
	                }
	            }
	        }
	        return array;
	    },
	    serializeParam:function (json) {
	        var strArr = [];
	        for (var i in json) {
	            //忽略默认的几个参数
	            if(i=="method" || i=="timeout" || i=="async") continue;
	            //传递过来的对象和函数不在提交之列
	            if (!((typeof json[i]).toLowerCase() == "function" || (typeof json[i]).toLowerCase() == "object")) {
	                strArr.push( encodeURIComponent(i) + "="+encodeURIComponent(json[i]) );
	            } else if (utils.isArray(json[i])) {
	                //支持传数组内容
	                for(var j = 0; j < json[i].length; j++) {
	                    strArr.push( encodeURIComponent(i) + "[]="+encodeURIComponent(json[i][j]) );
	                }
	            }
	        }
	        return strArr.join("&");
	    },
	    formatUrl:function (url) {
	        var u = url.replace(/&&/g, '&');
	        u = u.replace(/\?&/g, '?');
	        u = u.replace(/&$/g, '');
	        u = u.replace(/&#/g, '#');
	        u = u.replace(/&+/g, '&');
	        return u;
	    },
	    isCrossDomainUrl:function (url) {
	        var a = document.createElement('a');
	        a.href = url;
	        if (browser.ie) {
	            a.href = a.href;
	        }
	        return !(a.protocol == location.protocol && a.hostname == location.hostname &&
	        (a.port == location.port || (a.port == '80' && location.port == '') || (a.port == '' && location.port == '80')));
	    },
	    clearEmptyAttrs : function(obj){
	        for(var p in obj){
	            if(obj[p] === ''){
	                delete obj[p]
	            }
	        }
	        return obj;
	    },
	    str2json : function(s){

	        if (!utils.isString(s)) return null;
	        if (window.JSON) {
	            return JSON.parse(s);
	        } else {
	            return (new Function("return " + utils.trim(s || '')))();
	        }

	    },
	    json2str : (function(){

	        if (window.JSON) {

	            return JSON.stringify;

	        } else {

	            var escapeMap = {
	                "\b": '\\b',
	                "\t": '\\t',
	                "\n": '\\n',
	                "\f": '\\f',
	                "\r": '\\r',
	                '"' : '\\"',
	                "\\": '\\\\'
	            };

	            function encodeString(source) {
	                if (/["\\\x00-\x1f]/.test(source)) {
	                    source = source.replace(
	                        /["\\\x00-\x1f]/g,
	                        function (match) {
	                            var c = escapeMap[match];
	                            if (c) {
	                                return c;
	                            }
	                            c = match.charCodeAt();
	                            return "\\u00"
	                            + Math.floor(c / 16).toString(16)
	                            + (c % 16).toString(16);
	                        });
	                }
	                return '"' + source + '"';
	            }

	            function encodeArray(source) {
	                var result = ["["],
	                    l = source.length,
	                    preComma, i, item;

	                for (i = 0; i < l; i++) {
	                    item = source[i];

	                    switch (typeof item) {
	                        case "undefined":
	                        case "function":
	                        case "unknown":
	                            break;
	                        default:
	                            if(preComma) {
	                                result.push(',');
	                            }
	                            result.push(utils.json2str(item));
	                            preComma = 1;
	                    }
	                }
	                result.push("]");
	                return result.join("");
	            }

	            function pad(source) {
	                return source < 10 ? '0' + source : source;
	            }

	            function encodeDate(source){
	                return '"' + source.getFullYear() + "-"
	                + pad(source.getMonth() + 1) + "-"
	                + pad(source.getDate()) + "T"
	                + pad(source.getHours()) + ":"
	                + pad(source.getMinutes()) + ":"
	                + pad(source.getSeconds()) + '"';
	            }

	            return function (value) {
	                switch (typeof value) {
	                    case 'undefined':
	                        return 'undefined';

	                    case 'number':
	                        return isFinite(value) ? String(value) : "null";

	                    case 'string':
	                        return encodeString(value);

	                    case 'boolean':
	                        return String(value);

	                    default:
	                        if (value === null) {
	                            return 'null';
	                        } else if (utils.isArray(value)) {
	                            return encodeArray(value);
	                        } else if (utils.isDate(value)) {
	                            return encodeDate(value);
	                        } else {
	                            var result = ['{'],
	                                encode = utils.json2str,
	                                preComma,
	                                item;

	                            for (var key in value) {
	                                if (Object.prototype.hasOwnProperty.call(value, key)) {
	                                    item = value[key];
	                                    switch (typeof item) {
	                                        case 'undefined':
	                                        case 'unknown':
	                                        case 'function':
	                                            break;
	                                        default:
	                                            if (preComma) {
	                                                result.push(',');
	                                            }
	                                            preComma = 1;
	                                            result.push(encode(key) + ':' + encode(item));
	                                    }
	                                }
	                            }
	                            result.push('}');
	                            return result.join('');
	                        }
	                }
	            };
	        }

	    })()

	};
utils.each(['String', 'Function', 'Array', 'Number', 'RegExp', 'Object', 'Date'], function (v) {
    utils['is' + v] = function (obj) {
        return Object.prototype.toString.apply(obj) == '[object ' + v + ']';
    }
});
var ajax = function() {

    //创建一个ajaxRequest对象
    var fnStr = 'XMLHttpRequest()';
    try {
        new ActiveXObject("Msxml2.XMLHTTP");
        fnStr = 'ActiveXObject(\'Msxml2.XMLHTTP\')';
    } catch (e) {
        try {
            new ActiveXObject("Microsoft.XMLHTTP");
            fnStr = 'ActiveXObject(\'Microsoft.XMLHTTP\')'
        } catch (e) {
        }
    }
    var creatAjaxRequest = new Function('return new ' + fnStr);


    /**
     * 将json参数转化成适合ajax提交的参数列表
     * @param json
     */
    function json2str(json) {
        var strArr = [];
        for (var i in json) {
            //忽略默认的几个参数
            if(i=="method" || i=="timeout" || i=="async" || i=="dataType" || i=="callback") continue;
            //忽略控制
            if(json[i] == undefined || json[i] == null) continue;
            //传递过来的对象和函数不在提交之列
            if (!((typeof json[i]).toLowerCase() == "function" || (typeof json[i]).toLowerCase() == "object")) {
                strArr.push( encodeURIComponent(i) + "="+encodeURIComponent(json[i]) );
            } else if (utils.isArray(json[i])) {
            //支持传数组内容
                for(var j = 0; j < json[i].length; j++) {
                    strArr.push( encodeURIComponent(i) + "[]="+encodeURIComponent(json[i][j]) );
                }
            }
        }
        return strArr.join("&");
    }

    function doAjax(url, ajaxOptions) {
        var xhr = creatAjaxRequest(),
        //是否超时
            timeIsOut = false,
        //默认参数
            defaultAjaxOptions = {
                method:"POST",
                timeout:5000,
                async:true,
                data:{},//需要传递对象的话只能覆盖
                onsuccess:function() {
                },
                onerror:function() {
                }
            };

        if (typeof url === "object") {
            ajaxOptions = url;
            url = ajaxOptions.url;
        }
        if (!xhr || !url) return;
        var ajaxOpts = ajaxOptions ? utils.extend(defaultAjaxOptions,ajaxOptions) : defaultAjaxOptions;

        var submitStr = json2str(ajaxOpts);  // { name:"Jim",city:"Beijing" } --> "name=Jim&city=Beijing"
        //如果用户直接通过data参数传递json对象过来，则也要将此json对象转化为字符串
        if (!utils.isEmptyObject(ajaxOpts.data)){
            submitStr += (submitStr? "&":"") + json2str(ajaxOpts.data);
        }
        //超时检测
        var timerID = setTimeout(function() {
            if (xhr.readyState != 4) {
                timeIsOut = true;
                xhr.abort();
                clearTimeout(timerID);
            }
        }, ajaxOpts.timeout);

        var method = ajaxOpts.method.toUpperCase();
        var str = url + (url.indexOf("?")==-1?"?":"&") + (method=="POST"?"":submitStr+ "&noCache=" + +new Date);
        xhr.open(method, str, ajaxOpts.async);
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4) {
                if (!timeIsOut && xhr.status == 200) {
                    ajaxOpts.onsuccess(xhr);
                } else {
                    ajaxOpts.onerror(xhr);
                }
            }
        };
        if (method == "POST") {
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            xhr.send(submitStr);
        } else {
            xhr.send(null);
        }
    }

    function doJsonp(url, opts) {

        var successhandler = opts.onsuccess || function(){},
            scr = document.createElement('SCRIPT'),
            options = opts || {},
            charset = options['charset'],
            callbackField = options['jsonp'] || 'callback',
            callbackFnName,
            timeOut = options['timeOut'] || 0,
            timer,
            reg = new RegExp('(\\?|&)' + callbackField + '=([^&]*)'),
            matches;

        if (utils.isFunction(successhandler)) {
            callbackFnName = 'bd__editor__' + Math.floor(Math.random() * 2147483648).toString(36);
            window[callbackFnName] = getCallBack(0);
        } else if(utils.isString(successhandler)){
            callbackFnName = successhandler;
        } else {
            if (matches = reg.exec(url)) {
                callbackFnName = matches[2];
            }
        }

        url = url.replace(reg, '\x241' + callbackField + '=' + callbackFnName);

        if (url.search(reg) < 0) {
            url += (url.indexOf('?') < 0 ? '?' : '&') + callbackField + '=' + callbackFnName;
        }

        var queryStr = json2str(opts);  // { name:"Jim",city:"Beijing" } --> "name=Jim&city=Beijing"
        //如果用户直接通过data参数传递json对象过来，则也要将此json对象转化为字符串
        if (!utils.isEmptyObject(opts.data)){
            queryStr += (queryStr? "&":"") + json2str(opts.data);
        }
        if (queryStr) {
            url = url.replace(/\?/, '?' + queryStr + '&');
        }

        scr.onerror = getCallBack(1);
        if( timeOut ){
            timer = setTimeout(getCallBack(1), timeOut);
        }
        createScriptTag(scr, url, charset);

        function createScriptTag(scr, url, charset) {
            scr.setAttribute('type', 'text/javascript');
            scr.setAttribute('defer', 'defer');
            charset && scr.setAttribute('charset', charset);
            scr.setAttribute('src', url);
            document.getElementsByTagName('head')[0].appendChild(scr);
        }

        function getCallBack(onTimeOut){
            return function(){
                try {
                    if(onTimeOut){
                        options.onerror && options.onerror();
                    }else{
                        try{
                            clearTimeout(timer);
                            successhandler.apply(window, arguments);
                        } catch (e){}
                    }
                } catch (exception) {
                    options.onerror && options.onerror.call(window, exception);
                } finally {
                    options.oncomplete && options.oncomplete.apply(window, arguments);
                    scr.parentNode && scr.parentNode.removeChild(scr);
                    window[callbackFnName] = null;
                    try {
                        delete window[callbackFnName];
                    }catch(e){}
                }
            }
        }
    }

    return {
        /**
         * 根据给定的参数项，向指定的url发起一个ajax请求。 ajax请求完成后，会根据请求结果调用相应回调： 如果请求
         * 成功， 则调用onsuccess回调， 失败则调用 onerror 回调
         * @method request
         * @param { URLString } url ajax请求的url地址
         * @param { Object } ajaxOptions ajax请求选项的键值对，支持的选项如下：
         * @example
         * ```javascript
         * //向sayhello.php发起一个异步的Ajax GET请求, 请求超时时间为10s， 请求完成后执行相应的回调。
         * UE.ajax.requeset( 'sayhello.php', {
         *
         *     //请求方法。可选值： 'GET', 'POST'，默认值是'POST'
         *     method: 'GET',
         *
         *     //超时时间。 默认为5000， 单位是ms
         *     timeout: 10000,
         *
         *     //是否是异步请求。 true为异步请求， false为同步请求
         *     async: true,
         *
         *     //请求携带的数据。如果请求为GET请求， data会经过stringify后附加到请求url之后。
         *     data: {
         *         name: 'ueditor'
         *     },
         *
         *     //请求成功后的回调， 该回调接受当前的XMLHttpRequest对象作为参数。
         *     onsuccess: function ( xhr ) {
         *         console.log( xhr.responseText );
         *     },
         *
         *     //请求失败或者超时后的回调。
         *     onerror: function ( xhr ) {
         *          alert( 'Ajax请求失败' );
         *     }
         *
         * } );
         * ```
         */

        /**
         * 根据给定的参数项发起一个ajax请求， 参数项里必须包含一个url地址。 ajax请求完成后，会根据请求结果调用相应回调： 如果请求
         * 成功， 则调用onsuccess回调， 失败则调用 onerror 回调。
         * @method request
         * @warning 如果在参数项里未提供一个key为“url”的地址值，则该请求将直接退出。
         * @param { Object } ajaxOptions ajax请求选项的键值对，支持的选项如下：
         * @example
         * ```javascript
         *
         * //向sayhello.php发起一个异步的Ajax POST请求, 请求超时时间为5s， 请求完成后不执行任何回调。
         * UE.ajax.requeset( 'sayhello.php', {
         *
         *     //请求的地址， 该项是必须的。
         *     url: 'sayhello.php'
         *
         * } );
         * ```
         */
		request:function(url, opts) {
            if (opts && opts.dataType == 'jsonp') {
                doJsonp(url, opts);
            } else {
                doAjax(url, opts);
            }
		},
        getJSONP:function(url, data, fn) {
            var opts = {
                'data': data,
                'oncomplete': fn
            };
            doJsonp(url, opts);
		}
	};


}();